Data locking protocols are commonly used to manage access to shared data in a multi-processing environment. In a typical locking protocol, processes seeking read or write access to a data resource acquire locks to the resource to prevent incompatible accesses. For example, a process seeking to update a data resource (e.g., through a write operation or other data-modifying operation), requests an exclusive lock to the resource from a master process for that resource. After the master process grants the exclusive lock to the requester process, the requester process obtains a local copy of the resource, for example from a disk drive or other persistent storage, then performs update operations on the local copy, rendering the corresponding content of the persistent storage stale. Other requests to access the data resource are denied by the master pending release of the exclusive lock by the prior requester process. By serializing access to the data resource in this way, loss of data coherency is avoided as the subsequent requester processes are prevented from accessing stale data.
Not all accesses to shared resources must be serialized. For example, multiple shared locks may typically be held simultaneously by processes seeking to read the same data resource, as no loss of coherency will occur due to the order in which the read accesses take place. By contrast, if a requester process requests an exclusive lock to a data resource while a shared lock is open (i.e., shared lock granted and not yet released), the master process may deny the exclusive lock request until the shared lock is released to ensure that no out-of-order access occurs.
One contingency that locking protocols must usually account for is failure of a processing node. Referring to FIG. 1, for example, each of N processing nodes 105 within prior-art database system 100 may concurrently execute any number of processes that seek access to data in a shared data storage 101. In one possible sequence of events, a process executing on Node 1 acquires an exclusive lock to a shared data resource 101 containing data D1 (indicated in FIG. 1 by arrow I11); updates D1 to produce D2 (112); records the update operation in a redo log 103 (113); then fails before D2 is written back to the data resource 101, the non-operation being indicated by dashed line 114. In this failure scenario, subsequent access to the shared data storage is restricted to ensure that no operations are performed on the now stale data, D1, with the level of restriction depending on the nature of the locking protocol.
In one prior-art locking protocol, a single process referred to herein as a centralized lock manager acts as the resource master for all shared resources in the database system. When a node fails, the centralized lock manager may continue to grant access to data resources that were not exclusively locked by the failed node. Thus, the centralized lock manager enables at least limited access to the shared data storage while the update operations performed by the failed node are recovered. On the downside, because all lock requests are directed to the centralized lock manager, the centralized lock manager tends to be a scalability bottleneck, degrading system performance as the number of processes and lock requests grows. Also, the centralized lock manager constitutes a single point of failure. If the node executing the centralized lock manager fails, all locking activity ceases, in effect rendering the shared data storage inaccessible and resulting in system-wide failure.
In another prior-art locking protocol, mastership of shared data resources is distributed among multiple lock manager processes each being executed by a respective one of the processing nodes 105. Thus, each processing node is a master for a subset of the shared resources. When a processing node fails, locking activity is temporarily halted and mastership of the resources mastered in the failed node is redistributed among the surviving nodes. Locking activity is resumed after the surviving nodes have completed applying the changes recorded in the redo log for the failed node. Although the single point failure and scalability limitations of the centralized lock manager approach are avoided, access to the shared data resources is denied until resource mastership is redistributed among the surviving nodes and the surviving nodes complete redoing the changes recorded in the redo log for the failed node.
Another prior-art locking protocol replicates mastership for each shared resource in two or more processing nodes, referred to as siblings. When the master for a particular resource fails, the sibling for the failed node will still have the locking information for the shared resource so that locking activity may continue during the recovery process. Unfortunately this replicated mastership approach substantially increases the amount of inter-process communication required for resource locking, decreasing system performance and limiting system scalability.
In yet another prior-art locking protocol coarse-grained locks are issued to enable exclusive or shared access to multiple data resources. Once a process acquires a coarse-grained lock, all data resources covered by that lock can be accessed even after a processing node failure, because the process owning the coarse-grained lock is assured that the failed node could not have modified any of the data resources. However, because many of the locked data resources may not actually be accessed by the lock holding process, coarse-grained locks tend to substantially increase false contention, leading to poor run-time performance.